home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Development Platforms / Apple II / Apple II Sample Code / APW.SC / SC04Cust.Ctrl / BC.DProc.asm2 < prev    next >
Encoding:
Text File  |  1990-06-24  |  42.0 KB  |  1,232 lines  |  [TEXT/pdos]

  1. *******************************************************************************
  2. *
  3. * BoxCtl CDEFProc -- Version 3.0
  4. *
  5. * (C)  Copyright Apple Computer, Inc. 1988-1990
  6. * All rights reserved.
  7. *
  8. * Developer Technical Support Apple II Sample Code
  9. *
  10. * by Keith Rollin
  11. *
  12. *******************************************************************************
  13. *
  14. myDragCtl           start
  15. *
  16. * Description:      Drag command. We hit something. Determine what it was and
  17. *                   drag it around the screen. If we hit the frame, then drag
  18. *                   the whole control. If we hit a knob, then we grow the
  19. *                   control (just like growing a window).
  20. *
  21. *
  22. * Inputs:           NONE
  23. *
  24. * Outputs:          NONE
  25. *
  26. * External Refs:
  27. *                   Import SetMyPen
  28. *                   Import Snap2Grid
  29. *                   Import myDrawCtl
  30. *                   Import FindPart
  31. *                   Import SetCtlRect
  32. *
  33. * Entry Points:     NONE
  34. *
  35. *******************************************************************************
  36.                     using CtlData
  37.  
  38.                     PushLong #oldPenState ; save drawing state, as we change it
  39.                     _GetPenState
  40.  
  41.                     ldy #6              ; make a working copy of CtlRect.
  42. loop100             lda myCtlRect,y
  43.                     sta drag_rect,y
  44.                     dey
  45.                     dey
  46.                     bpl loop100
  47.  
  48.                     pha                 ; has the mouse been lifted up?
  49.                     PushWord #mUpMask   ; ask for any such events
  50.                     PushLong #TrackEvent
  51.                     _GetNextEvent
  52.                     pla
  53.  
  54.                     lda TrackEvent+owhat
  55.                     cmp #mouseUpEvt     ; was there a mouse up event?
  56.                     bne mDown           ; no - so start tracking
  57.                     brl done            ; yes - so leave
  58.  
  59. mDown               ANOP
  60.                     PushLong #TrackEvent+owhere
  61.                     _GlobalToLocal
  62.  
  63.                     lda TrackEvent+owhere
  64.                     sta OldMouse        ; FindPart likes the mouse Position
  65.                     sta theParam        ; in 'theParam'
  66.                     lda TrackEvent+owhere+2
  67.                     sta OldMouse+2
  68.                     sta theParam+2
  69.  
  70.                     jsr FindPart        ; what did we hit? (returns internal
  71.                     sta dragPart        ;   partcode number).
  72.  
  73.                     cmp #InteriorPart+1 ; what part did we hit?
  74.                     bge GrowFrame       ; some knob - grow the control
  75.                     brl DragFrame       ; interior or frame - move the control
  76.  
  77. ;
  78. ; This part of the program is called when we detect that we have clicked on
  79. ; a grow knob. It tracks the motions of the mouse, and grows/draws the
  80. ; control appropriately.
  81. ;
  82. GrowFrame           ANOP
  83.                     PushWord #2         ; set us to XOR mode. This is for the
  84.                     _SetPenMode         ; rubber-banding effect of growing.
  85.  
  86.                     jsr SetMyPen        ; set my pen's width
  87.  
  88.                     PushLong #GreyPattern ; grow with a grey pattern
  89.                     _SetPenPat
  90.  
  91.                     ldy #oCtlMaxX       ; get local copies of the maximum
  92.                     ldx #6              ; and minimum dimensions.
  93. loop0010            lda [<CtlPtr],y
  94.                     sta MinY,x
  95.                     dey
  96.                     dey
  97.                     dex
  98.                     dex
  99.                     bpl loop0010
  100.  
  101. ; validate the min and max values. the min values must be at least $10.
  102. ; if not, they are set there. the max values must be at least as large
  103. ; as the min values. if not, they are set to $FFFF
  104.  
  105.                     lda #$10
  106.                     cmp MinX
  107.                     blt ckMinY
  108.                     sta MinX
  109.  
  110. ckMinY              cmp MinY
  111.                     blt ckMaxX
  112.                     sta MinY
  113.  
  114. ckMaxX              lda MaxX
  115.                     cmp MinX
  116.                     bge ckMaxY
  117. ChgX                lda #$FFFF
  118.                     sta MaxX
  119.  
  120. ckMaxY              lda MaxY
  121.                     cmp MinY
  122.                     bge doneCk
  123. ChgY                lda #$FFFF
  124.                     sta MaxY
  125. doneCk              ANOP
  126.  
  127. ;
  128. ; We grow the control with the following algorithm. First, setup by:
  129. ;
  130. ;  1. saving the current mouse postion in 'NewMouse',
  131. ;  2. aligning 'NewMouse' to the grid, and
  132. ;  3. making a working copy of the control's rectangle in 'drag_rect'.
  133. ;
  134. ; We then enter the main loop:
  135. ;
  136. ;  4. Draw a copy of the rubber-banding rectangle.
  137. ;  5. Check the mouse button. If it is up, goto #12
  138. ;  6. Put the position of the mouse into 'NewerMouse'. Align it to grid.
  139. ;  7. Check it against 'NewMouse'. If it hasn't changed, goto #5.
  140. ;  8. Erase the old rubber-Band.
  141. ;  9. Calculate the new rectangle and put it into 'drag_rect'
  142. ; 10. Move 'NewerMouse' into 'NewMouse'
  143. ; 11. Goto #4
  144. ;
  145. ; The growing is all done. Clean up and leave.
  146. ;
  147. ; 12. Erase the rubber band.
  148. ; 13. Erase the control.
  149. ; 14. Invalidate the area under the control
  150. ; 15. Make drag_rect the new boundary of the control
  151. ; 16. Say goodnite, Gracie.
  152. ;
  153.  
  154.                     lda OldMouse
  155.                     sta NewMouse
  156.                     lda OldMouse+2
  157.                     sta NewMouse+2
  158.  
  159.                     ldx #^NewMouse      ; make sure we are on the grid!!!
  160.                     lda #NewMouse
  161.                     jsr Snap2Grid
  162.  
  163. DrawLoop            ANOP
  164.                     PushLong #drag_rect ; draw the rubber-band
  165.                     _FrameRect
  166.  
  167. WaitLoop            ANOP
  168.                     pha                 ; has the mouse been lifted up?
  169.                     PushWord #mUpMask   ; ask for any such events
  170.                     PushLong #TrackEvent
  171.                     _GetNextEvent
  172.                     pla
  173.  
  174.                     lda TrackEvent+owhat
  175.                     cmp #mouseUpEvt
  176.                     beq done            ; mouse up occured - so leave.
  177.                     
  178.                     lda TrackEvent+owhere ; mouse still down. copy it to
  179.                     sta NewerMouse      ; NewerMouse
  180.                     lda TrackEvent+owhere+2
  181.                     sta NewerMouse+2
  182.                     
  183.                     PushLong #NewerMouse ; convert it to window coordinates.
  184.                     _GlobalToLocal
  185.  
  186.                     ldx #^NewerMouse    ; make sure the new position is on
  187.                     lda #NewerMouse     ; the grid.
  188.                     jsr Snap2Grid
  189.  
  190.                     lda NewerMouse      ; See if the mouse position moved. We
  191.                     cmp NewMouse        ; only redraw the rubber-band if it did.
  192.                     bne ReDraw          ; It did - redraw the rubber-band
  193.                     lda NewerMouse+2
  194.                     cmp NewMouse+2
  195.                     beq WaitLoop        ; No movement - check button state
  196.  
  197. ReDraw              ANOP
  198.                     PushLong #drag_rect ; erase the old rubber band
  199.                     _FrameRect
  200.  
  201.                     lda NewerMouse      ; copy NewerMouse for next loop
  202.                     sta NewMouse
  203.                     sec                 ; and update deltaXY for AdjFrameRect
  204.                     sbc OldMouse
  205.                     sta deltaY
  206.  
  207.                     lda NewerMouse+2
  208.                     sta NewMouse+2
  209.                     sec
  210.                     sbc OldMouse+2
  211.                     sta deltaX
  212.  
  213.                     jsr AdjFrameRect    ; adjust for drawing the new rect
  214.  
  215.                     brl DrawLoop        ; redraw the rubber-band
  216.  
  217. done                ANOP
  218.                     PushLong #drag_rect ; erase the rubber band
  219.                     _FrameRect
  220.  
  221.                     PushLong #myCtlRect ; erase the control
  222.                     _EraseRect
  223.  
  224.                     PushLong #myCtlRect ; invalidate the stuff under it
  225.                     _InvalRect
  226.  
  227.                     brl Exit
  228. ;
  229. ; This part of the program is called when we have clicked on either the
  230. ; frame or the interior. It calls dragrect to move an outline of the
  231. ; control around.
  232. ;
  233.  
  234. DragFrame           ANOP
  235.  
  236. ; Get the portRect of the window that owns this control. This rectangle
  237. ; will be used to control the limits of dragging.
  238.  
  239.                     ldy #octlOwner      ; get the pointer to the control's
  240.                     lda [<CtlPtr],y     ; owning window into 'work'
  241.                     sta <work
  242.                     iny
  243.                     iny
  244.                     lda [<CtlPtr],y
  245.                     sta <work+2
  246.  
  247.                     ldy #oportRect+6    ; copy the PortRect of the window
  248.                     ldx #6              ; out of its GrafPort into limitRect.
  249. loop400             lda [<work],y
  250.                     sta limitRect,x
  251.                     dey
  252.                     dey
  253.                     dex
  254.                     dex
  255.                     bpl loop400
  256.  
  257. ;
  258. ; Use dragRect to drag an outline of the control around the
  259. ; screen for me.
  260. ;
  261.                     pha                 ; space for result
  262.                     pha
  263.                     PushLong #DragDraw  ; no action proc
  264.                     PushLong #GreyPattern ; drag pattern
  265.                     PushLong OldMouse   ; starting location of mouse
  266.                     PushLong #drag_rect ; outline to drag
  267.                     PushLong #limitRect ; limitRect
  268.                     PushLong #limitRect ; slopRect
  269.                     PushWord #%00101000 ; custom drag flag, ReturnRect flag
  270.                     _DragRect
  271.  
  272.                     pla                 ; pull off and discard the deltas
  273.                     pla
  274.  
  275.                     PushLong #myCtlRect ; erase the control in its old pos'n
  276.                     _EraseRect
  277.  
  278.                     PushLong #myCtlRect ; invalidate the stuff under it
  279.                     _InvalRect
  280.  
  281.                     ldx #^drag_rect     ; align the new rectangle to the grid.
  282.                     lda #drag_rect
  283.                     jsr Snap2Grid
  284.  
  285. Exit                ANOP
  286.                     ldy #6              ; copy over the new control frame
  287. loop200             lda drag_rect,y
  288.                     sta myCtlRect,y
  289.                     dey
  290.                     dey
  291.                     bpl loop200
  292.  
  293.                     PushLong #myCtlRect ; Invalidate the new area under the
  294.                     _InvalRect          ; control so it will be redrawn.
  295.  
  296.                     PushLong #oldPenState
  297.                     _SetPenState        ; clean up QuickDraw after ourselves.
  298.  
  299.                     jsr SetCtlRect      ; copy new rect into control record
  300.  
  301.                     lda #-1             ; Say that we handled it
  302.                     tax
  303.  
  304.                     rts
  305.  
  306. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  307. ;
  308. ; Called by DragRect to draw the rectangle of the control. I draw the outline
  309. ; myself so that I can align it to my own grid. The normal aligning of the
  310. ; rectangle to the grid only aligns to powers of 2. I align to anything.
  311. ;
  312. ; When this routine is called, the stack looks like this:
  313. ;
  314. ;                   PUSH:WORD - delta X
  315. ;                   PUSH:WORD - delta Y
  316. ;                   PUSH:BYTE[3] - return address
  317. ;
  318. ; However, since I set the ReturnRect flag, I can ignore the deltas passed to
  319. ; me, and use drag_rect directly. I make a copy of it, make sure that it is
  320. ; aligned to the grid, draw it, remove the parameters, and return to the
  321. ; control manager.
  322. ;
  323.  
  324. DragDraw            ANOP
  325.  
  326. RTLAddr             equ 1
  327. DY                  equ RTLAddr+3
  328. DX                  equ DY+2
  329.  
  330.                     ldx #6              ; make a copy of the rectangle that
  331. loop500             lda drag_rect,x     ; _DragRect is passing to us. We are
  332.                     sta draw_rect,x     ; going to modify it so that it is
  333.                     dex                 ; aligned to the grid.
  334.                     dex
  335.                     bpl loop500
  336.  
  337.                     ldx #^draw_rect     ; align the new rectangle to the grid.
  338.                     lda #draw_rect
  339.                     jsr Snap2Grid
  340.  
  341. DrawOutline         ANOP
  342.                     PushLong #draw_rect
  343.                     _FrameRect
  344.  
  345. ExitDragDraw        ANOP
  346.                     lda 1,s             ; move the RTL address back up
  347.                     sta 5,s
  348.                     lda 2,s
  349.                     sta 6,s
  350.  
  351.                     pla                 ; remove the parameters (DX, DY)
  352.                     pla
  353.  
  354.                     rtl                 ; back to dragRect!!
  355.  
  356. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  357. ;
  358. ; Called by the routine that grows the control with a rubber-band
  359. ; sort of thing. It uses the part code we hit as an index into
  360. ; a table. This table contains a list of offsets into the
  361. ; 4 words of drag_rect. It reads in a pair of these offsets and
  362. ; uses them to modify the appropriate X/Y coordinates with
  363. ; deltaY and deltaX. DeltaY and deltaX are set up by the
  364. ; rubber-banding routine.
  365.  
  366. AdjFrameRect        ANOP
  367.                     ldx #6
  368. loop380             lda drag_rect,x
  369.                     sta new_rect,x
  370.                     dex
  371.                     dex
  372.                     bpl loop380
  373.  
  374.                     lda dragPart        ; get the part code we are dragging
  375.                     sec
  376.                     sbc #ULPart
  377.                     asl a               ; turn it into an index.
  378.                     asl a
  379.                     tax
  380.                     lda PtToAdj,x       ; get Y coordinate to adjust
  381.                     tay
  382.                     lda PtToAdj+2,x     ; get X coordinate to adjust
  383.                     tax
  384.  
  385. ; if the entry that was fetched from the table was -1, then that means
  386. ; that we are making no adjustments in that direction. For instance, it
  387. ; we are dragging on the top edge knob, we want to adjust just the top
  388. ; side of the rectangle, but want to leave either of the sides alone.
  389.  
  390.                     cpy #-1             ; modify the vertical coordinate
  391.                     beq NoChg1          ; of choice if necessary.
  392.                     clc
  393.                     lda deltaY
  394.                     adc myCtlRect,y
  395.                     sta new_rect,y
  396.  
  397. NoChg1              cpx #-1             ; modify the horizontal coordinate
  398.                     beq NoChg2          ; of choice if necessary.
  399.                     clc
  400.                     lda deltaX
  401.                     adc myCtlRect,x
  402.                     sta new_rect,x
  403.  
  404. NoChg2              ANOP
  405.                     ldx #^new_rect      ; align the rectangle to the grid.
  406.                     lda #new_rect
  407.                     jsr Snap2Grid
  408.  
  409. ; now that we have a new rectangle, we have to make sure that it is within
  410. ; the maximum and minimum sizes allowed.
  411.  
  412.                     sec                 ; make sure the new Y size is OK
  413.                     lda new_rect+4
  414.                     sbc new_rect
  415.                     bcc NoCopy1
  416.                     cmp MinY
  417.                     blt NoCopy1         ; it's not, so leave old coords there
  418.                     inc a
  419.                     cmp MaxY
  420.                     bge NoCopy1         ; it's not, so leave old coords there
  421.  
  422.                     lda new_rect        ; it is, so update it.
  423.                     sta drag_rect
  424.                     lda new_rect+4
  425.                     sta drag_rect+4
  426.  
  427. NoCopy1             ANOP
  428.                     sec                 ; make sure the new X size is OK
  429.                     lda new_rect+6
  430.                     sbc new_rect+2
  431.                     bcc NoCopy2
  432.                     cmp MinX
  433.                     blt NoCopy2         ; it's not, so leave old coords there
  434.                     inc a
  435.                     cmp MaxX
  436.                     bge NoCopy2         ; it's not, so leave old coords there
  437.  
  438.                     lda new_rect+2      ; it is, so update it
  439.                     sta drag_rect+2
  440.                     lda new_rect+6
  441.                     sta drag_rect+6
  442. NoCopy2             ANOP
  443.                     rts
  444.  
  445.  
  446. PtToAdj             dc i2'0,2,0,-1,0,6,-1,6,4,6,4,-1,4,2,-1,2'
  447.  
  448. TrackEvent          ds $10
  449.  
  450. OldMouse            ds 4
  451. NewMouse            ds 8
  452. NewerMouse          ds 8
  453. drag_rect           ds 8
  454. draw_rect           ds 8
  455. new_rect            ds 8
  456. limitRect           ds 8
  457. MinY                ds 2
  458. MinX                ds 2
  459. MaxY                ds 2
  460. MaxX                ds 2
  461.  
  462.                     end
  463.  
  464.                     EJECT
  465. *******************************************************************************
  466. *
  467. myNewValue          start
  468. *
  469. * Description:      Called when the value of the control is to be changed.
  470. *                   The area under the control is invalidated so that it will
  471. *                   be redrawn.
  472. *
  473. *
  474. * Inputs:           NONE
  475. *
  476. * Outputs:          NONE
  477. *
  478. * External Refs:
  479. *                   Import Snap2Grid
  480. *                   Import myDrawCtl
  481. *                   Import SetCtlRect
  482. *
  483. * Entry Points:     NONE
  484. *
  485. *******************************************************************************
  486.                     using CtlData
  487.  
  488.                     PushLong #myCtlRect ; erase old control
  489.                     _EraseRect
  490.  
  491.                     PushLong #myCtlRect ; invalidate area erased
  492.                     _InvalRect
  493.  
  494.                     ldx #^myCtlRect     ; make sure control is on the grid
  495.                     lda #myCtlRect
  496.                     jsr Snap2Grid
  497.  
  498.                     jsr SetCtlRect
  499.  
  500.                     lda #0              ; return no value
  501.                     tax
  502.  
  503.                     rts
  504.                     end
  505.  
  506.                     EJECT
  507. *******************************************************************************
  508. *
  509. mySetParams         start
  510. *
  511. * Description:      Set new parameters command. Don't set if either of them
  512. *                   are negative.
  513. *
  514. *
  515. * Inputs:           NONE
  516. *
  517. * Outputs:          NONE
  518. *
  519. * External Refs:    NONE
  520. *
  521. * Entry Points:     NONE
  522. *
  523. *******************************************************************************
  524.                     using CtlData
  525.  
  526.                     lda theParam        ; these have gotta go on in reverse
  527.                     sta <work+2
  528.                     lda theParam+2
  529.                     sta <work
  530.  
  531.                     ora <work+2         ; is this a NULL pointer?
  532.                     bne CopyIt          ; no - so use it
  533.  
  534.                     lda #^StdCtlData    ; yes - so set pointer to default data
  535.                     sta <work+2
  536.                     lda #StdCtlData
  537.                     sta <work
  538.  
  539. CopyIt              ANOP
  540.                     ldy #oCtlSize-2     ; copy the data into control record.
  541.                     ldx #oCtlSize-oCtlMinY-2
  542. loop                phy
  543.                     txy
  544.                     lda [<work],y
  545.                     ply
  546.                     sta [<CtlPtr],y
  547.                     dey
  548.                     dey
  549.                     dex
  550.                     dex
  551.                     bpl loop
  552.  
  553.                     lda #0              ; return no value
  554.                     tax
  555.  
  556.                     rts
  557.                     end
  558.  
  559.                     EJECT
  560. *******************************************************************************
  561. *
  562. myRecSize           start
  563. *
  564. * Description:      Return record size command.
  565. *
  566. *
  567. * Inputs:           NONE
  568. *
  569. * Outputs:          A = Size of the control record to allocate.
  570. *
  571. * External Refs:    NONE
  572. *
  573. * Entry Points:     NONE
  574. *
  575. *******************************************************************************
  576.                     using CtlData
  577.  
  578.                     lda #oCtlSize       ; low word of record size
  579.                     ldx #0              ; high word
  580.  
  581.                     rts
  582.                     end
  583.  
  584.                     EJECT
  585. *******************************************************************************
  586. *
  587. Null                start
  588. *
  589. * Description:      Null routine. Does nothing. Returns no error.
  590. *
  591. *
  592. * Inputs:           NONE
  593. *
  594. * Outputs:          NONE
  595. *
  596. * External Refs:    NONE
  597. *
  598. * Entry Points:     NONE
  599. *
  600. *******************************************************************************
  601.  
  602.                     lda #0
  603.                     tax
  604.  
  605.                     rts
  606.                     end
  607.  
  608.                     EJECT
  609. *******************************************************************************
  610. *
  611. InitCtlData         start
  612. *
  613. * Description:      Initialize some data that will needs to be handy: Get a
  614. *                   pointer to the control record (we are supplied only with
  615. *                   a handle), make a local copy of the control rectangle, set
  616. *                   up a pointer to a color table, and move CtlParam from a
  617. *                   Direct Page location into an absolute location.
  618. *
  619. *
  620. * Inputs:           NONE
  621. *
  622. * Outputs:          NONE
  623. *
  624. * External Refs:    NONE
  625. *
  626. * Entry Points:     NONE
  627. *
  628. *******************************************************************************
  629.                     using CtlData
  630.  
  631. ;
  632. ; Check to see if the Control Manager is sending us a 'RecSize' call. If it
  633. ; is, then we cannot rely on the validity of the Control handle, as it has not
  634. ; yet been allocated and is essentially garbage. Since we do not know what it
  635. ; points to, we don't want to read from it, as it may actually accidentally
  636. ; point to something dangerous, like the IWM I/O locations!!! So if we detect
  637. ; a RecSize code, skip over this routine.
  638. ;
  639.                     lda <CtlCode        ; is this a RecSize call?
  640.                     cmp #recSize
  641.                     beq done            ; yes - skip this whole routine
  642.  
  643. ;
  644. ; Copy the value in CtlParam into a local location -- off of the direct page.
  645. ; We do this for convenience. We may need to pass a pointer to CtlParam to
  646. ; a toolbox routine, but you can't do that for a direct page location. The
  647. ; number assiciated with a direct page location is really an offset off of the
  648. ; base specified by the Direct Page register; it is NOT an absolute memory
  649. ; location. So that we can conveniently use 'PushLong #location' if we need
  650. ; to, I copy CtlParam to a non-direct page location.
  651. ;
  652.                     lda <CtlParam
  653.                     sta theParam
  654.                     lda <CtlParam+2
  655.                     sta theParam+2
  656.  
  657.                     ldy #2              ; get a handy pointer to the CtlRec
  658.                     lda [<theCtlHandle],y
  659.                     sta <CtlPtr+2
  660.                     lda [<theCtlHandle]
  661.                     sta <CtlPtr
  662.  
  663.                     ldy #octlRect+6     ; copy the control rect over to the
  664.                     ldx #6              ; local variable.
  665. loop                lda [<CtlPtr],y
  666.                     sta myCtlRect,x
  667.                     dey
  668.                     dey
  669.                     dex
  670.                     dex
  671.                     bpl loop
  672.  
  673. ;
  674. ; The following values are used by Snap2Grid. However, Snap2Grid can be
  675. ; called with an invalid Direct Page, so we copy them out the control
  676. ; record (which is pointed to by a pointer in our Direct Page) and into
  677. ; some absolute locations that we can get to at all times.
  678. ;
  679.                     ldy #oCtlGridX      ; get the X and Y spacings out of the
  680.                     lda [<CtlPtr],y     ; control record and into some local
  681.                     sta myCtlGridX      ; storage for easy handling.
  682.  
  683.                     ldy #oCtlGridY
  684.                     lda [<CtlPtr],y
  685.                     sta myCtlGridY
  686.  
  687. ; Check the color table pointer. If it is non-zero, install it as the
  688. ; pointer to the color table we'll be using. If not, then install a
  689. ; pointer to a default color table.
  690.  
  691.                     ldy  #octlColor     ; Get the pointer to the color
  692.                     lda [<CtlPtr],y     ; table in the control record.
  693.                     sta ColorPtr        ; Save it to a local pointer.
  694.                     iny
  695.                     iny
  696.                     lda [<CtlPtr],y
  697.                     sta ColorPtr+2
  698.                     ora ColorPtr        ; is it a NULL pointer?
  699.                     bne done            ; no, so use it.
  700.  
  701.                     lda #StdColorTable  ; yes, install my own color table.
  702.                     sta ColorPtr
  703.                     lda #^StdColorTable
  704.                     sta ColorPtr+2
  705.  
  706. done                ANOP
  707.                     rts
  708.  
  709.                     end
  710.  
  711.                     EJECT
  712. *******************************************************************************
  713. *
  714. SetCtlRect          start
  715. *
  716. * Description:      This routine is called when the control's bounding
  717. *                   rectangle has been changed and needs to be written back
  718. *                   out to the control record.
  719. *
  720. *
  721. * Inputs:           NONE
  722. *
  723. * Outputs:          NONE
  724. *
  725. * External Refs:    NONE
  726. *
  727. * Entry Points:     NONE
  728. *
  729. *******************************************************************************
  730.                     using CtlData
  731.  
  732.                     ldy #octlRect+6     ; get an offset into the control rec.
  733.                     ldx #6              ; index to my local record.
  734. loop                ANOP
  735.                     lda myCtlRect,x
  736.                     sta [<CtlPtr],y
  737.                     dey
  738.                     dey
  739.                     dex
  740.                     dex
  741.                     bpl loop
  742.  
  743.                     rts
  744.  
  745.                     end
  746.  
  747.                     EJECT
  748. *******************************************************************************
  749. *
  750. SetMyPen            start
  751. *
  752. * Description:      We want our control to look good in both 320 and 640 mode.
  753. *                   Because vertical lines are thinner in 640 than 320, its a
  754. *                   good idea to draw them doubly thick just so they can be
  755. *                   seen. This routine will determine what mode we are in and
  756. *                   adjust the pen accordingly.
  757. *
  758. *
  759. * Inputs:           NONE
  760. *
  761. * Outputs:          NONE
  762. *
  763. * External Refs:    NONE
  764. *
  765. * Entry Points:     NONE
  766. *
  767. *******************************************************************************
  768.                     using CtlData
  769.  
  770.                     pha                 ; we base pen width on the MasterSCB
  771.                     _GetMasterSCB
  772.                     pla
  773.                     and #$0080          ; check the mode bit
  774.                     beq pen320          ; we are in 320 mode - go push a 1
  775.  
  776.                     PushWord #2         ; in 640 mode - push on a 2 width
  777.                     bra setpn
  778.  
  779. pen320              PushWord #1         ; in 320 mode - push on a 1 width
  780.  
  781. setpn               ANOP                ; width is 1 or 2
  782.                     PushWord #1         ; Height is always 1
  783.                     _SetPenSize
  784.  
  785.                     rts
  786.                     end
  787.  
  788.                     EJECT
  789. *******************************************************************************
  790. *
  791. CalcCorners         start
  792. *
  793. * Description:      This routine calculates the rectangles for all of the
  794. *                   little knobs that are used to grow the control. They are
  795. *                   stored locally - not with the control record - and so need
  796. *                   to be calculated every time we need to check for hits or
  797. *                   to draw the control.
  798. *
  799. *
  800. * Inputs:           NONE
  801. *
  802. * Outputs:          knobXXX, FrameHeight, FrameWidth variables are initialized.
  803. *
  804. * External Refs:    NONE
  805. *
  806. * Entry Points:     NONE
  807. *
  808. *******************************************************************************
  809.                     using CtlData
  810.  
  811. top                 equ 0               ; alias these to something a little
  812. left                equ 2               ; more descriptive.
  813. bottom              equ 4
  814. right               equ 6
  815.  
  816. ; Get the size of the knobs. The height and width are stored in the CtlValue
  817. ; field in a packed format. This unpacks them and stores them locally for
  818. ; ease of access.
  819.  
  820.                     ldy #octlValue
  821.                     lda [<CtlPtr],y
  822.                     and #$00FF
  823.                     sta FrameHeight
  824.                     lda [<CtlPtr],y
  825.                     xba
  826.                     and #$00FF
  827.                     sta FrameWidth
  828.  
  829. ;
  830. ; We "assembly line" the initialization of the knob rectangles. Instead
  831. ; of calculating just one knob at a time, we do a few of them all at the
  832. ; same time. Here we initialize the tops and bottoms of the 3 top knobs.
  833.  
  834.                     lda myCtlRect+top
  835.                     sta knobUL+top
  836.                     sta knobTop+top
  837.                     sta knobUR+top
  838.                     clc
  839.                     adc FrameHeight
  840.                     sta knobUL+bottom
  841.                     sta knobTop+bottom
  842.                     sta knobUR+bottom
  843.  
  844. ;
  845. ; Initialize the lefts and rights of the three left knobs.
  846. ;
  847.                     lda myCtlRect+left
  848.                     sta knobUL+left
  849.                     sta knobLeft+left
  850.                     sta knobLL+left
  851.                     clc
  852.                     adc FrameWidth
  853.                     sta knobUL+right
  854.                     sta knobLeft+right
  855.                     sta knobLL+right
  856.  
  857. ;
  858. ; Initialize the tops and bottoms of the three bottom knobs.
  859. ;
  860.                     lda myCtlRect+bottom
  861.                     sta knobLL+bottom
  862.                     sta knobBottom+bottom
  863.                     sta knobLR+bottom
  864.                     sec
  865.                     sbc FrameHeight
  866.                     sta knobLL+top
  867.                     sta knobBottom+top
  868.                     sta knobLR+top
  869.  
  870. ;
  871. ; Initialize the lefts and rights of the three right knobs.
  872. ;
  873.                     lda myCtlRect+right
  874.                     sta knobUR+right
  875.                     sta knobRight+right
  876.                     sta knobLR+right
  877.                     sec
  878.                     sbc FrameWidth
  879.                     sta knobUR+left
  880.                     sta knobRight+left
  881.                     sta knobLR+left
  882.  
  883. ;
  884. ; At this point, the 4 corner knobs have been completely initialized.
  885. ; If we are going to be using the edge knobs, then we'll have to do
  886. ; some extra math. However, if we aren't, then we'll skip over the
  887. ; math.
  888.  
  889.                     ldy #octlFlag
  890.                     lda [<CtlPtr],y
  891.                     and #knobEdgeMask
  892.                     beq done
  893.  
  894. ; Do extra setup for edge knobs
  895. ;
  896. ; First, get top and bottom coordinates for the side edges:
  897. ;
  898. ;     top = (myCtlRect.top + myCtlRect.bottom - FrameHeight)/2
  899. ;     bot = (myCtlRect.top + myCtlRect.bottom + FrameHeight)/2
  900.  
  901.                     clc
  902.                     lda myCtlRect+top
  903.                     adc myCtlRect+bottom
  904.                     pha
  905.                     adc FrameHeight
  906.                     lsr a
  907.                     sta knobLeft+bottom
  908.                     sta knobRight+bottom
  909.                     pla
  910.                     sec
  911.                     sbc FrameHeight
  912.                     lsr a
  913.                     sta knobLeft+top
  914.                     sta knobRight+top
  915.  
  916. ;
  917. ; Now perform similar calculations for the left and right sides
  918. ; of the top and bottom edge knobs.
  919. ;
  920.                     clc
  921.                     lda myCtlRect+left
  922.                     adc myCtlRect+right
  923.                     pha
  924.                     adc FrameWidth
  925.                     lsr a
  926.                     sta knobTop+right
  927.                     sta knobBottom+right
  928.                     pla
  929.                     sec
  930.                     sbc FrameWidth
  931.                     lsr a
  932.                     sta knobTop+left
  933.                     sta knobBottom+left
  934.  
  935. done                ANOP
  936.                     rts
  937.                     end
  938.  
  939.                     EJECT
  940. *******************************************************************************
  941. *
  942. Snap2Grid           start
  943. *
  944. * Description:      This control defproc lets the application optionally create
  945. *                   an invisible grid based on local coordinates. When this is
  946. *                   done, the 4 corners of the control are always aligned to
  947. *                   the coordinates of this grid. This occurs when we drag or
  948. *                   resize the control, or call MoveControl. Snap2Grip is the
  949. *                   routine that ensures we are on the grid.
  950. *
  951. *
  952. * Inputs:           A = low word of pointer to rectangle to fix
  953. *                   X = high word
  954. *
  955. * Outputs:          rectangle is modified in place.
  956. *
  957. * External Refs:    NONE
  958. *
  959. * Entry Points:     NONE
  960. *
  961. *******************************************************************************
  962.                     using CtlData
  963.  
  964. oldD                equ 1
  965. oldB                equ oldD+2
  966. rectPtr             equ oldB+1
  967.  
  968. ;
  969. ; We are going to use a local direct page here. This is because Snap2Grid is
  970. ; called by my routine that draws the control's recangle as it is being
  971. ; dragged. When that happens, we are not using our normal direct page, and
  972. ; hence can't use any of the values or work locations there. So we set up
  973. ; another one with it's own workspace.
  974. ;
  975.                     phx                 ; save the pointer to the rectangle
  976.                     pha
  977.  
  978.                     phb                 ; save the caller's data bank register
  979.                     phd                 ; save the caller'd direct page reg.
  980.  
  981.                     phk                 ; switch data bank to program bank
  982.                     plb
  983.  
  984.                     tsc                 ; switch direct page to stack pointer
  985.                     tcd
  986.  
  987.  
  988. ;
  989. ; WhchGridYX is used to help generalize this routine. We support different
  990. ; spacings in the X and Y directions of the grid. As we loop through all 4
  991. ; coordinates of the rectangle, we want to make sure that we are using the
  992. ; correct spacing. 'whichGridYX' holds flags that tell us when to use X and
  993. ; when to use Y spacing (0 = use Y spacing; 1 = use X spacing).
  994. ;
  995.                     lda #%0101          ; Set up some indices into GridYX
  996.                     sta whichGridYX
  997.  
  998. ;
  999. ; Fix the coordinates by using the following method:
  1000. ;
  1001. ;  1. Get the difference between the coordinate we are examining and
  1002. ;     the next lowest grid location:
  1003. ;
  1004. ;          z = coordinate mod GridSize
  1005. ;
  1006. ;  2. Z tells how far away from the next lowest grid line
  1007. ;     the coordinate we are looking at is, so subtracting that
  1008. ;     value will put the coordinate on the grid.
  1009. ;
  1010. ;          coordinate := coordinate - z
  1011. ;
  1012. ;  3. However, this is simply truncating, and I don't like the
  1013. ;     way that feels when resizing the control. So lets add an
  1014. ;     instruction so that it ROUNDS instead.
  1015. ;
  1016. ;          if z > GridSize/2 then
  1017. ;               coordinate := coordinate + GridSize
  1018. ;
  1019.  
  1020.                     ldy #6              ; init our loop index
  1021. Loop                ANOP
  1022.                     sty YSave
  1023.  
  1024.                     lda whichGridYX     ; do we now use X or Y grid spacing?
  1025.                     and #%0001
  1026.                     beq UseY
  1027.                     lda myCtlGridX
  1028.                     bra UseIt
  1029. UseY                ANOP
  1030.                     lda myCtlGridY
  1031.  
  1032. ; we now have the gridsize in the Acc
  1033. UseIt               ANOP
  1034.                     cmp #2              ; Is it 0 or 1? If so, then skip over
  1035.                     blt ShortCircuit    ;   dividing routine.
  1036.                     sta GridSize        ; save this for the divide later.
  1037.  
  1038.                     pha                 ; push space on stack for the result
  1039.                     pha                 ; of the divide we are going to do.
  1040.  
  1041.                     lda [<rectPtr],y    ; push on the coordinate we are
  1042.                     pha                 ;   adjusting as the Dividend
  1043.                     PushWord GridSize   ; push this on as the divisor
  1044.                     _UDivide            ; unsigned divide
  1045.                     pla                 ; quotient - we don't want it.
  1046.                     PullWord Remainder  ; remainder is 'z' - Keep it!
  1047.  
  1048.                     ldy YSave           ; get my coordinate index back.
  1049.                     lda [<rectPtr],y    ; get the coordinate to change
  1050.                     sec
  1051.                     sbc Remainder       ; change it
  1052.                     sta [<rectPtr],y    ; save it back out
  1053.  
  1054.                     lda GridSize        ; Make a GridSize/2
  1055.                     lsr a
  1056.                     cmp Remainder       ; is remainder < GridSize/2?
  1057.                     bge ShortCircuit    ; yes - so we're done
  1058.                     lda [<rectPtr],y    ; no - so bump the coordinate
  1059.                     clc
  1060.                     adc GridSize
  1061.                     sta [<rectPtr],y
  1062.  
  1063. ShortCircuit        lsr whichGridYX     ; move the next index into place
  1064.                     dey                 ; bump down to the next coordinate
  1065.                     dey                 ;   of the rectangle.
  1066.                     bpl Loop
  1067.  
  1068. Exit                ANOP
  1069.                     pld                 ; restore caller's Direct Page reg.
  1070.                     plb                 ; restore data bank register
  1071.                     pla                 ; remove rect pointer
  1072.                     pla
  1073.                     rts                 ; all done - go bye-bye
  1074.  
  1075. whichGridYX         ds 2
  1076. YSave               ds 2
  1077. Remainder           ds 2
  1078. GridSize            ds 2
  1079.  
  1080.                     end
  1081.  
  1082.                     EJECT
  1083. *******************************************************************************
  1084. *
  1085. FindPart            start
  1086. *
  1087. * Description:      This routine is called to find out exactly which part of
  1088. *                   the control we clicked in. It first checks to see if we
  1089. *                   clicked in any of the grow knobs. If so, then it returns
  1090. *                   an 'internal partcode' telling the calling routine which
  1091. *                   knob was clicked in. If a knob wasn't clicked in, a check
  1092. *                   is made to see if we clicked on the frame. If we are
  1093. *                   allowed to click in the interior, a check is made to see
  1094. *                   if we clicked there, too.
  1095. *
  1096. *
  1097. * Inputs:           NONE
  1098. *
  1099. * Outputs:          A = internal partcode of part hit (1-10)
  1100. *
  1101. * External Refs:
  1102. *                   Import CalcCorners
  1103. *
  1104. * Entry Points:
  1105. *                   entry TestFrame     ; called by myTestCtl
  1106. *
  1107. *******************************************************************************
  1108.                     using CtlData
  1109.  
  1110.                     jsr CalcCorners
  1111.  
  1112. ;
  1113. ; We first check to see if the mouse was clicked in any of the knobs. We do
  1114. ; this by assuming a knob was clicked in, and then checking to see if that was
  1115. ; true. If so, we leave here with the partcode we assumed. If not, we loop
  1116. ; through and check all of the other knobs. If none of the knobs was clicked
  1117. ; in, we see if the frame was clicked on.
  1118.  
  1119.                     ldx #LeftPart       ; get last knob's part code
  1120.                     ldy #7*8            ; point to last knob's rect
  1121.  
  1122. loop                ANOP
  1123.                     phx                 ; save partcode we're checking for...
  1124.                     phy                 ; and the rect's pointer
  1125.  
  1126.                     pha                 ; space for _PtInRect result
  1127.                     PushLong #theParam  ; push on the point to check
  1128.                     lda #^knobUL        ; create a pointer to the rect
  1129.                     pha
  1130.                     clc                 ; Bumping just the low byte is OK
  1131.                     tya                 ;   unless the GS suddenly lets
  1132.                     adc #knobUL         ;   code segments cross bank
  1133.                     pha                 ;   boundaries
  1134.                     _PtInRect
  1135.                     pla                 ; get result of PtInRect
  1136.                     ply                 ; retrieve rectangle index
  1137.                     plx                 ; retrieve part code
  1138.                     cmp #0              ; did we score a hit?
  1139.                     bne InKnob          ; yes, return with the part code
  1140.                     dex                 ; move down to next partcode
  1141.                     sec                 ; move down to next rectangle
  1142.                     tya
  1143.                     sbc #8
  1144.                     tay
  1145.                     bpl loop            ; keep going until rect index < 0
  1146.  
  1147.                     bra TestFrame       ; not in knobs - try frame
  1148.  
  1149. ;
  1150. ; We just scored a hit on one of the knobs, and X holds the knob number.
  1151. ; However, the application may not have corner or edge knobs active. So
  1152. ; if we clicked on an inactive knob, have to check for that and return
  1153. ; 'inFrame' instead of a knob partcode.
  1154. ;
  1155. InKnob              ANOP
  1156.                     ldy #octlFlag       ; are corner knobs active?
  1157.                     lda [<CtlPtr],y
  1158.                     and #knobCornerMask
  1159.                     bne ckEdge          ; yes - so pass this code on.
  1160.  
  1161.                     txa                 ; Corners not allowed. Did we hit one?
  1162.                     lsr a
  1163.                     bcs RetFramePart    ; yes, so return click on Frame instead
  1164.  
  1165. ckEdge              ANOP
  1166.                     ldy #octlFlag       ; are edge knobs active?
  1167.                     lda [<CtlPtr],y
  1168.                     and #knobEdgeMask
  1169.                     bne done            ; yes - so return this code
  1170.  
  1171.                     txa                 ; Edges not allowed. Did we hit one?
  1172.                     lsr a
  1173.                     bcs TestFrame       ; no, so pass this code on.
  1174. RetFramePart        ANOP
  1175.                     ldx #FramePart      ; yes, so return click on Frame instead
  1176. done                ANOP
  1177.                     txa                 ; put the part code in the Acc
  1178.                     rts
  1179.  
  1180. TestFrame           entry
  1181.  
  1182. ; First test to see if it is within the Control's rectangle. It should
  1183. ; be, but let's check anyway...
  1184.  
  1185.                     pha
  1186.                     PushLong #theParam
  1187.                     PushLong #myCtlRect
  1188.                     _PtInRect
  1189.                     pla
  1190.                     beq NotInFrame      ; no in the frame. Signal noPart
  1191.  
  1192. ; Now see if we differentiate between the frame and the interior
  1193.  
  1194.                     ldy #octlFlag
  1195.                     lda [<CtlPtr],y
  1196.                     and #dragIntMask
  1197.                     bne RetFramePart    ; nope - everything drags
  1198.  
  1199. ; Yes we do. Now see if we hit the frame fair and square. Inset the
  1200. ; control's bounding rectangle by the size of the knobs that are on
  1201. ; it to create an inner rectangle. If we fall between those two
  1202. ; rectangles, then I say that you have landed on the frame. If we
  1203. ; got this far, then we know that we are within the outer rectangle.
  1204. ; Now see if we are outside of the inner rectangle.
  1205.  
  1206.                     ldx #6              ; make a copy of the control rect
  1207. CopyLoop            lda myCtlRect,x     ; so that we can reduce it.
  1208.                     sta innerRect,x
  1209.                     dex
  1210.                     dex
  1211.                     bpl CopyLoop
  1212.  
  1213.                     PushLong #innerRect ; push on pointer to the rect to inset
  1214.                     PushWord FrameWidth ; push on the amounts to inset it by
  1215.                     PushWord FrameHeight ; (these vals inited by CalcCorners)
  1216.                     _InsetRect
  1217.  
  1218.                     pha                 ; see if we are outside of the inner
  1219.                     PushLong #theParam  ; rectangle
  1220.                     PushLong #innerRect
  1221.                     _PtInRect
  1222.  
  1223.                     pla                 ; check the result
  1224.                     beq RetFramePart    ; we were between rects!
  1225.  
  1226. NotInFrame          lda #noPart         ; Not *exactly* on the frame.
  1227.                     rts
  1228.  
  1229. innerRect           ds 8
  1230.  
  1231.                     end
  1232.